/*
    SEL - Simple DirectMedia Layer Extension Library
    Copyright (C) 2001, 2002 Matej Knopp <knopp@users.sf.net>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef __sel_debug_h__
#define __sel_debug_h__

#include <iostream>

#define DEBUG

namespace debug
{
#ifdef DEBUG
	//! Holds the state of the debugging channels.
	/*!
	  \sa channel_enabled
	  \sa enable_channel
	  \sa enable_channels
	 */
	extern bool channels[256];

	//! Specifies if debugging is enabled.
	/*!
	  \sa init
	 */
	extern bool enabled;

	//! Query whether the specified channel is enabled.
	/*!
	  \param channel - the number of queried channel
	 */
	inline bool channel_enabled (int channel)
	{
		return enabled ? channels[channel] : false;
	}

	//! Enable or disable specified channel.
	/*!
	  \param channel - the number of channel to be enabled/disabled
	  \param enable - whether to enable or disable the channel
	  \sa enable_channels
	 */
	inline void enable_channel (int channel, bool enable = true)
	{
		channels[channel] = enable;
	}

	//! Enable or disable the channels in given range.
	/*!
	  By default all the channels are enabled (or disabled).
	  \param enable - whether the channels will be enabled or disabled
	  \param min - the lower bound of range
	  \param max - the upper bound of range
	  \sa enable_channel
	 */
	inline void enable_channels (bool enable = true, int min = 0, int max =
				    255)
	{
		for (int i = min; i <= max; i++)
			channels[i] = enable;
	}

	//! Turn the debugging on and off.
	void init (bool enable);

//! Execute code \a arg, if debugging is enabled.
/*!
  \param arg - code to be executed
 */
#define debugA(arg) { if (debug::enabled) { arg; } }

//! Write text followed by a new line to the standard error.
/*!
  \param arg - text to be sent to stderr
 */
#define debug(arg) debugA (std::cerr << arg << std::endl)

//! Execute code \a arg, if debug channel \a n is enabled.
/*!
  \param n - the debug channel
  \param arg - code to be executed
 */
#define debugNA(n, arg) { if (debug::channel_enabled (n)) { arg; } }

//! Write text followed by the end of line to standard
//! error, if debug channel \a n is enabled.
/*!
  \param n - the debug channel
  \param arg - text to be send to cerr
 */
#define debugN(n, arg) debugNA (n, std::cerr << arg << std::endl)

//! Mark that shows current position in the source code.
#define MARK "*** " __FILE__ << ":" << __LINE__ << " *** " << __PRETTY_FUNCTION__ << " ***"

//! Extension of MARK prepending `*** WARNING '.
/*!
  \see MARK
 */
#define WARNING_MARK "*** WARNING " << MARK << std::endl << "  "

//! Write WARNING_MARK and some text to stderr, if debugging is enabled.
/*!
  \param arg - text to be written
  \see WARNING_MARK
 */
#define s_warning(arg) { if (debug::enabled) { std::cerr << WARNING_MARK << arg << std::endl;} }

//! Assert if some condition is true.
/*!
  If the condition \arg is false, the macro writes warning with
  assertion and the condition to the stderr (if debugging is enabled)

  \param arg - the condition to be checked
  \see warning
 */
#define s_assert(arg) { if (!(arg)) { warning ("Assertion `" << #arg << "' failed!") } }

#else

	inline bool channel_enabled (int channel)
	{
		return 0;
	}

	inline void enable_channel (int channel, bool enable = true)
	{
	}

	inline void enable_channels (bool enable = true, int min = 0, int max =
				    255)
	{
	}

	inline void init (bool enable)
	{
	}

#define debugA(arg)
#define debug(arg)
#define debugNA(n, arg)
#define debugN(n, arg)
#define MARK
#define WARNING_MARK
#define s_warning(arg)
#define s_assert(arg)
#endif // DEBUG

	// channels
	const int sel_internal = 1;

#define debugI(arg) debugN(debug::sel_internal, arg)

#define return_if_fail(arg) { if (!(arg)) { s_warning ("Assertion `" << #arg << "' failed!"); return; } }
#define return_val_if_fail(arg, val) { if (!(arg)) { s_warning ("Assertion `" << #arg << "' failed!"); return (val); } }

#ifndef __sel_disable_warning
#  ifdef warning
#    undef warning
#  endif // warning
#  define warning s_warning
#endif // __sel_disable_warning

} // namespace SEL

#endif // __sel_debug_h__
